package factorytest.iflytek.com.einkiflytekfactorytest.engineer_test;

import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.Nullable;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import factorytest.iflytek.com.einkiflytekfactorytest.R;
import factorytest.iflytek.com.einkiflytekfactorytest.common.FTUtils;
import factorytest.iflytek.com.einkiflytekfactorytest.myrecorder.IRecordListener;
import factorytest.iflytek.com.einkiflytekfactorytest.myrecorder.RecorderThread;
import factorytest.iflytek.com.einkiflytekfactorytest.playerutils.MediaPlayerTool;
import factorytest.iflytek.com.einkiflytekfactorytest.utils.DebugLog;
import factorytest.iflytek.com.einkiflytekfactorytest.utils.executor.AppExecutors;

public class FragmentES7210_MonoTest extends BaseFragment implements View.OnClickListener{
    private static final String RECORDER_FILE_PATH = FTUtils.getFTStorageDirectory() + File.separator + "mic_es7210.pcm";
    private static final String RECORDER_MONO_FILE_PATH = FTUtils.getFTStorageDirectory() + File.separator + "mic_es7210_mono.pcm";

    private final int SampleRateInHz = 16000;

    private final static int STATE_WANT_RECORD = 0;
    private final static int STATE_WANT_PLAY = STATE_WANT_RECORD + 1;
    private final static int STATE_WANT_CHECK = STATE_WANT_PLAY + 1;

    private int recordState = STATE_WANT_RECORD;

    private TextView txtInfo;
    private TextView txtStatus;
    private Button btnPass;
    private Button btnFail;
    private Button btnRepeat;
    private Button btnRecordAndPlay;

    private MediaPlayerTool mediaPlayerTool;

    //先左后右
    private MicInfoAttr micInfoAttr = MicInfoAttr.left;

    private OnBtnResultForES7210 onBtnResultForES7210;

    public void setOnBtnResultForES7210(OnBtnResultForES7210 onBtnResultForES7210) {
        this.onBtnResultForES7210 = onBtnResultForES7210;
    }

    @Override
    protected int getLayoutRes() {
        return R.layout.fragment_engineer_es7210_mono_test;
    }

    @Override
    protected void onInitView(@Nullable Bundle savedInstanceState) {

        txtInfo = (TextView) findViewById(R.id.txtInfo);
        txtStatus = (TextView) findViewById(R.id.txtStatus);
        btnPass = (Button) findViewById(R.id.btnPass);
        btnFail = (Button) findViewById(R.id.btnFail);
        btnRepeat = (Button) findViewById(R.id.btnRepeat);
        btnRecordAndPlay = (Button) findViewById(R.id.btnRecordAndPlay);

//        txtStatus.setVisibility(View.INVISIBLE);

        btnPass.setOnClickListener(this);
        btnFail.setOnClickListener(this);
        btnRepeat.setOnClickListener(this);
        btnRecordAndPlay.setOnClickListener(this);

        DebugLog.e("getHandler = " + getHandler());

        mediaPlayerTool = MediaPlayerTool.getInstance(getContext(), getHandler());

        AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
        int maxVolume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
        am.setStreamVolume(AudioManager.STREAM_MUSIC, maxVolume, 0);

    }

    private volatile boolean isHeadsetRegistered = false;
    @Override
    protected void onVisible() {
        super.onVisible();

        doOnVisible();
    }

    private void doOnVisible() {
        updateMicInfo();
        setBtnPassFailGone(true);
        txtStatus.setText("");
        btnRepeat.setEnabled(false);

//        updateBtnUI(recordState);

//        if (!isHeadsetRegistered) {
//            isHeadsetRegistered = true;
//            //发送广播检测耳机插入状态
//            IntentFilter filter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
//            mContext.registerReceiver(headsetPlugReceiver, filter);
//        }
    }

    @Override
    protected void onInvisible() {
        super.onInvisible();
        stopRecord();
        stopPlay();

//        if (isHeadsetRegistered) {
//            isHeadsetRegistered = false;
//            mContext.unregisterReceiver(headsetPlugReceiver);
//        }
    }

//    private void updateBtnUI(int state) {

//        if (state == STATE_WANT_RECORD) {
//
//            setBtnPassFailGone(true);
//            btnRecordAndPlay.setText(R.string.mic_record);
//
//            txtStatus.setVisibility(View.INVISIBLE);
//
//        } else if (state == STATE_WANT_PLAY) {
//
//            setBtnPassFailGone(true);
//            btnRecordAndPlay.setText(R.string.mic_play);
//
//            txtStatus.setVisibility(View.VISIBLE);
//            txtStatus.setText(R.string.mic_status_recording);
//
//
//        } else if (state == STATE_WANT_CHECK) {
//
//            setBtnPassFailGone(false);
//            txtStatus.setVisibility(View.VISIBLE);
//            txtStatus.setText(R.string.mic_status_playing);
//
//        }
//
//        txtInfo.setText(micInfoAttr.getInfoResId());
//        btnPass.setText(micInfoAttr.getPassResId());
//        btnFail.setText(micInfoAttr.getFailResId());
//    }

    private void setBtnPassFailGone(boolean gone) {
//        btnPass.setVisibility(gone ? View.INVISIBLE : View.VISIBLE);
//        btnFail.setVisibility(gone ? View.INVISIBLE : View.VISIBLE);
        btnPass.setEnabled(!gone);
        btnFail.setEnabled(!gone);

//        btnRecordAndPlay.setVisibility(gone ? View.VISIBLE : View.INVISIBLE);

    }

    @Override
    public void onClick(View v) {

        if (v == btnRecordAndPlay) {

//            recordState++;
//            updateBtnUI(recordState);

//            if (recordState == STATE_WANT_PLAY) {
//                startRecord();
//            } else if (recordState == STATE_WANT_CHECK) {
//                stopRecord();
//                startPlay();
//            }


            updateMicInfo();

            stopPlay();
            startRecord();

            setBtnPassFailGone(true);

            txtStatus.setText(R.string.mic_status_recording);
            setBtnRecordEnabled(false);

            getHandler().sendEmptyMessageDelayed(MSG_RECORD_OVER, DELAY_RECORD_OVER);


        } else if (v == btnPass) {

            onClickBtnPassOrFail();

            if (micInfoAttr == MicInfoAttr.left) {

                micInfoAttr = MicInfoAttr.right;

            } else if (micInfoAttr == MicInfoAttr.right) {

                if (onBtnResultForES7210 != null) {
                    onBtnResultForES7210.onBtnResultForES7210(true);
                    findViewById(R.id.btnFail).setSelected(false);
                    findViewById(R.id.btnPass).setSelected(false);
                    v.setSelected(true);
                } else {
                    micInfoAttr = MicInfoAttr.left;
                }

            }

//            recordState = STATE_WANT_RECORD;
//            updateBtnUI(recordState);

            updateMicInfo();

        } else if (v == btnFail) {

            onClickBtnPassOrFail();

            if (onBtnResultForES7210 != null) {
                onBtnResultForES7210.onBtnResultForES7210(false);
                findViewById(R.id.btnFail).setSelected(false);
                findViewById(R.id.btnPass).setSelected(false);
                v.setSelected(true);
            }
        } else if (v == btnRepeat) {
            startPlay();
        }

    }

    private void onClickBtnPassOrFail() {
        btnRepeat.setEnabled(false);
        stopRecord();
        stopPlay();
        getHandler().postDelayed(new Runnable() {
            @Override
            public void run() {
                txtStatus.setText("");
            }
        }, 200);
    }

    private void updateMicInfo() {
        txtInfo.setText(micInfoAttr.getInfoResId());
        btnPass.setText(micInfoAttr.getPassResId());
        btnFail.setText(micInfoAttr.getFailResId());
    }

    private void setBtnRecordEnabled(boolean enabled) {
        Button btnRecord = (Button) findViewById(R.id.btnRecordAndPlay);
        if (btnRecord == null) {
            return;
        }
        btnRecord.setEnabled(enabled);
    }

    //////////////////////
    //    play
    /////////////////////
    private void startPlay() {

        stopPlay();
        mediaPlayerTool.playPcm(RECORDER_MONO_FILE_PATH);

        getHandler().postDelayed(new Runnable() {
            @Override
            public void run() {
                txtStatus.setText(R.string.mic_status_playing);

            }
        }, 300);

    }

    private void stopPlay() {
        mediaPlayerTool.stop();
        txtStatus.setText(R.string.mic_status_playing_stop);

    }

    //////////////////////
    //    Recorder
    /////////////////////
    private RecorderThread recorderThread;


    public void startRecord() {
        startRecordTread();
    }

    private void stopRecord() {
        stopRecordThread();

    }

    private void startRecordTread() {

        if (recorderThread != null) {
            stopRecordThread();
        }

        recorderThread = new RecorderThread("es7210-", null, RECORDER_FILE_PATH);
        recorderThread.getRecorderOperator().setSampleRateInHz(SampleRateInHz);
        recorderThread.getRecorderOperator().setChannelConfig(AudioFormat.CHANNEL_IN_STEREO);
        recorderThread.getRecorderOperator().setAudioFormat(AudioFormat.ENCODING_PCM_FLOAT);
        recorderThread.getRecorderOperator().setRecordingListener(recordListener);
        recorderThread.start();

    }

    private void stopRecordThread() {

        if (recorderThread != null) {
            recorderThread.joinThread();
            recorderThread = null;
        }
    }

    private volatile boolean keepAlive = true;
    private BlockingQueue<ByteBuffer> audioDataQueue = new LinkedBlockingQueue<>(128);

    private Runnable saveMonoRunnable = new Runnable() {
        @Override
        public void run() {
            BufferedOutputStream bos = null;

            try {

                File file = new File(RECORDER_MONO_FILE_PATH);
                if (file.exists()) {
                    file.delete();
                }
                bos = new BufferedOutputStream(new FileOutputStream(file));

                keepAlive = true;
                while (keepAlive) {

                    ByteBuffer byteBuffer = audioDataQueue.take();
                    if (byteBuffer != null && byteBuffer.array().length != 1) {

                        byte[] buffer = new byte[byteBuffer.array().length / 2];
                        for (int n = 0, i = 0; n < byteBuffer.array().length; ) {
                            if (micInfoAttr == MicInfoAttr.right) {
                                n += 4;
                                i += 2;
                            }

                            n++;
                            n++;
                            buffer[i++] = byteBuffer.array()[n++];
                            buffer[i++] = byteBuffer.array()[n++];

                            if (micInfoAttr == MicInfoAttr.left) {
                                n += 4;
                                i += 2;
                            }
                        }

                        bos.write(buffer, 0, buffer.length);
                        bos.flush();
                        buffer = null;
                        byteBuffer = null;
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            } finally {

                audioDataQueue.clear();

                DebugLog.e("write file finish..........................");

                if (bos != null) {
                    try {
                        bos.flush();
                        bos.close();
                    } catch (IOException ignored) {
                    }
                }
            }
        }
    };

    private IRecordListener recordListener = new IRecordListener() {

        @Override
        public void onRecordingData(byte[] audioData, int validSize) {

            int size = Math.min(audioData.length, validSize);

            audioDataQueue.add(ByteBuffer.wrap(audioData, 0, size));

        }

        @Override
        public void onRecordingStart() {

            AppExecutors.runOnIoThread(saveMonoRunnable);
            AppExecutors.postToMainThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(mContext, R.string.record_start, Toast.LENGTH_SHORT).show();
                }
            });
        }

        @Override
        public void onRecordingStop() {

            keepAlive = false;
            //保证saveMonoRunnable能退出
            byte[] buffer = new byte[1];
            audioDataQueue.add(ByteBuffer.wrap(buffer, 0, buffer.length));

            AppExecutors.postToMainThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(mContext, R.string.record_stop, Toast.LENGTH_SHORT).show();
                }
            });
        }
    };
    //////////////////////////

//    private BroadcastReceiver headsetPlugReceiver = new BroadcastReceiver() {
//
//        @Override
//        public void onReceive(Context context, Intent intent) {
//            final String action = intent.getAction();
//
//            if (action != null && action.equals(Intent.ACTION_HEADSET_PLUG)) {
//                if (intent.hasExtra("state")) {
//                    boolean unplug = (intent.getIntExtra("state", 0) == 0);
//                    DebugLog.e("unplug = " + unplug);
//
//                    setBtnRecordEnabled(unplug);
//
//                }
//            }
//        }
//    };

    private final int MSG_RECORD_OVER = 10;
    private final int DELAY_RECORD_OVER = 5000;
    @Override
    protected void handleMessage(Message msg) {
        super.handleMessage(msg);
        DebugLog.e("msg.what = " + msg.what);
        if (msg.what == MediaPlayerTool.EVENT_PLAY_OVER) {
            txtStatus.setText(R.string.mic_status_playing_stop);
        } else if (msg.what == MSG_RECORD_OVER) {
            stopRecord();
            startPlay();
            setBtnPassFailGone(false);
            setBtnRecordEnabled(true);
            btnRepeat.setEnabled(true);

        }
    }

    private enum MicInfoAttr {
        left(R.string.mic_info_left, R.string.mic_result_left_pass, R.string.mic_result_left_fail),
        right(R.string.mic_info_right, R.string.mic_result_right_pass, R.string.mic_result_right_fail),
        ;

        private final int infoResId;
        private final int passResId;
        private final int failResId;

        MicInfoAttr(int infoResId, int passResId, int failResId) {
            this.infoResId = infoResId;
            this.passResId = passResId;
            this.failResId = failResId;
        }

        public int getInfoResId() {
            return infoResId;
        }

        public int getPassResId() {
            return passResId;
        }

        public int getFailResId() {
            return failResId;
        }
    }

}
